//-----------------------------------------------------------------------
// <copyright file="Create.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Sdc.Tasks.BizTalk2006.SendPort
{
    using System;
    using Microsoft.BizTalk.ExplorerOM;
    using System.Globalization;
    
    /// <summary>
    /// Creates a send port.
    /// </summary>
    /// <remarks>
    /// <code>
    /// <![CDATA[<BizTalk2006.SendPort.Create 
    ///     Name="name" 
    ///     Application="Test Application"
    ///     IsDynamic="isDynamic" 
    ///     IsTwoWay="isTwoWay" 
    ///     Prority="priority" 
    ///     SendPipeline="sendPipeline" 
    ///     ReceivePipeline="receivePipeline" 
    ///     TrackingTypes="trackingTypes" 
    ///     Filter="filter" 
    ///     InboundMaps="inboundMaps" 
    ///     OutboundMaps="outboundMaps" 
    ///     PrimaryTransportAddress="transportAddress" 
    ///     PrimaryTransportDeliveryNotification="deliveryNotification" 
    ///     PrimaryTransportName="transportName"
    ///     PrimaryTransportOrderedDelivery="orderedDelivery" 
    ///     PrimaryTransportProtocolName="protocolName" 
    ///     PrimaryTransportRetryCount="retryCount" 
    ///     PrimaryTransportRetryInterval="retryInterval" 
    ///     PrimaryTransportServiceWindowEnabled="serviceWindowEnabled" 
    ///     PrimaryTransportServiceWindowStartTime="serviceWindowStartTime" 
    ///     PrimaryTransportServiceWindowEndTime="serviceWindowEndTime" 
    ///     PrimaryTransportTransportData="transportData" 
    ///     PrimaryTransportSendHandler="SendHandler"
    ///     SecondaryTransportAddress="transportAddress" 
    ///     SecondaryTransportDeliveryNotification="deliveryNotification" 
    ///     SecondaryTransportName="transportName"
    ///     SecondaryTransportOrderedDelivery="orderedDelivery" 
    ///     SecondaryTransportProtocolName="protocolName" 
    ///     SecondaryTransportRetryCount="retryCount" 
    ///     SecondaryTransportRetryInterval="retryInterval" 
    ///     SecondaryTransportServiceWindowEnabled="serviceWindowEnabled" 
    ///     SecondaryTransportServiceWindowStartTime="serviceWindowStartTime" 
    ///     SecondaryTransportServiceWindowEndTime="serviceWindowEndTime" 
    ///     SecondaryTransportTransportData="transportData" 
    ///     SecondaryTransportSendHandler="SendHandler"
    ///     SendPipelineData="xml string"
    ///     ReceivePipelineData="xml string"
    ///     RouteFailedMessage="true"
    ///     StopSendingOnFailure="false"
    ///     OrderedDelivery="false"
    ///     Server="server" 
    ///     Database="database" />]]>
    /// </code>
    /// <para>where:</para>
    /// <para><i>name (Required)</i></para>
    /// <para>
    /// The name of the send port.
    /// </para>
    /// <para><i>Application (Required)</i></para>
    /// <para>
    /// The application to create the send port in
    /// </para>
    /// <para><i>IsDynamic</i></para>
    /// <para>
    /// <b>true</b> of the send port is dynamic, or <b>false</b> if it is static. The default is <b>false</b>.
    /// </para>
    /// <para><i>IsTwoWay</i></para>
    /// <para>
    /// <b>true</b> of the send port is two way, or <b>false</b> if it is one way. The default is <b>false</b>.
    /// </para>
    /// <para><i>Priority</i></para>
    /// <para>
    /// A number between 1 (highest) and 10 (lowest) which is the priority of the send port. The default is 5.
    /// </para>
    /// <para><i>SendPipeline (Required)</i></para>
    /// <para>
    /// The assembly qualified name of the send pipeline.
    /// </para>
    /// <para><i>ReceivePipeline</i></para>
    /// <para>
    /// The assembly qualified name of the receive pipeline. This must be specified if the send port is two way, and is
    /// ignored if it is one way.
    /// </para>
    /// <para><i>TrackingTypes</i></para>
    /// <para>
    /// The types of tracking implemented by the port. This can be a combination of the following values seperated by
    /// semi colons: TrackPropertiesAfterReceivePipeline;TrackPropertiesAfterSendPipeline;TrackPropertiesBeforeReceivePipelineTrackPropertiesBeforeSendPipeline. The default is no tracking.
    /// </para>
    /// <para><i>Filter</i></para>
    /// <para>
    /// An XML string representing the filter expression for the port. See the BizTalk documentation for details of this
    /// format. The default is no filter.
    /// </para>
    /// <para><i>InboundMaps</i></para>
    /// <para>
    /// An itemgroup of the assembly qualified names of inbound maps for the port. The default is no inbound maps.
    /// Example: <![CDATA[	<ItemGroup>
	///	<SendPortServicingSystem-SPOutboundMaps Include="Microsoft.Samples.BizTalk.SouthridgeVideo.OrderBrokerMaps.CSR_OrderRequest_To_Order,Microsoft.Samples.BizTalk.SouthridgeVideo.OrderBrokerMaps, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1fb25adc93e1ab92"></SendPortServicingSystem-SPOutboundMaps>
	/// </ItemGroup>]]>
    /// </para>
    /// <para><i>OutboundMaps</i></para>
    /// <para>
    /// An itemgroup of the assembly qualified names of outbound maps for the port. The default is no outbound maps.
    /// </para>
    /// <para><i>PrimaryTransportAddress (Required for primary, required for secondary if two way)</i></para>
    /// <para>
    /// The address (often called the URI) for the transport.
    /// </para>
    /// <para><i>PrimaryTransportDeliveryNotification</i></para>
    /// <para>
    /// The types of delivery notification for the transport, which must be one of the following values: None, Transmitted.
    /// The default is None.
    /// </para>
    /// <para><i>PrimaryTransportTransportName (Required for primary, required for secondary if two way)</i></para>
    /// <para>
    /// The name of the transport.
    /// </para>
    /// <para><i>PrimaryTransportOrderedDelivery</i></para>
    /// <para>
    /// <b>true</b> to specify ordered delivery for a transport, or <b>false</b> otherwise. The default is <b>false</b>. Note
    /// that not all adapters support ordered delivery.
    /// </para>
    /// <para><i>PrimaryTransportProtocolName (Required for primary, required for secondary if two way)</i></para>
    /// <para>
    /// The name of the protocol for the transport.
    /// </para>
    /// <para><i>PrimaryTransportRetryCount</i></para>
    /// <para>
    /// The number of retries that the transport can use to send or receive a message.
    /// </para>
    /// <para><i>PrimaryTransportRetryInterval</i></para>
    /// <para>
    /// The interval between retries of sending or receiving a message. The units of this are determined by the specific
    /// type of adapter, however minutes is the most common unit.
    /// </para>
    /// <para><i>PrimaryTransportServiceWindowEnabled</i></para>
    /// <para>
    /// <b>true</b> to enable a service window for the transport, or <b>false</b> if it is always active. If this is <b>true</b>
    /// then the start and end times for the window must be specified. The default is <b>false</b>.
    /// </para>
    /// <para><i>PrimaryTransportServiceWindowStartTime</i></para>
    /// <para>
    /// The start time for the service window in the format HH:mm:ss. This must be supplied if the service window is
    /// enabled, and is ignored if the service window is not enabled.
    /// </para>
    /// <para><i>PrimaryTransportServiceWindowEndTime</i></para>
    /// <para>
    /// The end time for the service window in the format HH:mm:ss. This must be supplied if the service window is
    /// enabled, and is ignored if the service window is not enabled.
    /// </para>
    /// <para><i>PrimaryTransportTransportData</i></para>
    /// <para>
    /// An XML string of adapter specific initialization data. Some of these formats are documented in the BizTalk
    /// documentation. This data can be created by configuring a send port manually and then examining it using
    /// the BizTalk API.
    /// </para>
    /// <para><i>Server</i></para>
    /// <para>
    /// The logical name of the server hosting the BizTalk management database. If neither this nor the
    /// database name are specified then the installation will default to the local installation.
    /// </para>
    /// <para><i>Database</i></para>
    /// <para>
    /// The name of the BizTalk management database. If neither this nor the server name are specified 
    /// then the installation will default to the local installation.
    /// </para>
    /// <para>
    /// Note that all the above parameters that relate to the PrimaryTransport can also be used for the secondary
    /// transport by replacing PrimaryTransport with SecondaryTransport
    /// </para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <BizTalk2006.SendPort.Create
    ///             Name="Test Send Port 1"
    ///             IsDynamic="false"
    ///             IsTwoWay="true"
    ///             Priority="3"
    ///             SendPipeline="Microsoft.BizTalk.DefaultPipelines.PassThruTransmit, Microsoft.BizTalk.DefaultPipelines, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
    ///             ReceivePipeline="Microsoft.BizTalk.DefaultPipelines.XMLReceive, Microsoft.BizTalk.DefaultPipelines, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
    ///             TrackingTypes="TrackPropertiesAfterReceivePipeline;TrackPropertiesAfterSendPipeline"
    ///             Filter="&lt;Filter&gt;&lt;Group&gt;&lt;Statement Property=&quot;BTS.ReceivePortName&quot; Operator=&quot;0&quot; Value=&quot;ReceivePortA&quot;/&gt;&lt;/Group&gt;&lt;/Filter&gt;"
    ///             InboundMaps="@(SendPortHistoryInsert-Test-SPInboundMaps)"
    ///             OutboundMaps="@(SendPortHistoryInsert-Test-SPOutboundMaps)"
    ///             PrimaryTransportAddress="http://localhost/senddata.aspx"
    ///             PrimaryTransportDeliveryNotification="Transmitted"
    ///             PrimaryTransportName="Test Transport 1"
    ///             PrimaryTransportOrderedDelivery="false"
    ///             PrimaryTransportProtocolName="HTTP"
    ///             PrimaryTransportRetryCount="10"
    ///             PrimaryTransportRetryInterval="5"
    ///             PrimaryTransportServiceWindowEnabled="true"
    ///             PrimaryTransportServiceWindowStartTime="09:00:00"
    ///             PrimaryTransportServiceWindowEndTime="17:30:00"    
    ///             PrimaryTransportTransportData="&lt;CustomProps&gt;&lt;ContentType vt=&quot;8&quot;&gt;text/xml&lt;/ContentType&gt;&lt;RequestTimeout vt=&quot;3&quot;&gt;0&lt;/RequestTimeout&gt;&lt;MaxRedirects vt=&quot;3&quot;&gt;5&lt;/MaxRedirects&gt;&lt;UseHandlerProxySettings vt=&quot;8&quot;&gt;-1&lt;/UseHandlerProxySettings&gt;&lt;UseProxy vt=&quot;8&quot;&gt;-1&lt;/UseProxy&gt;&lt;ProxyName vt=&quot;8&quot;&gt;sdfsd&lt;/ProxyName&gt;&lt;ProxyPort vt=&quot;3&quot;&gt;80&lt;/ProxyPort&gt;&lt;ProxyUsername vt=&quot;8&quot;&gt;Somename&lt;/ProxyUsername&gt;&lt;ProxyPassword vt=&quot;8&quot;&gt;Somepassword&lt;/ProxyPassword&gt;&lt;AuthenticationScheme vt=&quot;8&quot;&gt;Basic&lt;/AuthenticationScheme&gt;&lt;Username vt=&quot;8&quot;&gt;Somename&lt;/Username&gt;&lt;Password vt=&quot;8&quot;&gt;Somepassword&lt;/Password&gt;&lt;Certificate vt=&quot;8&quot;&gt;AAAA BBBB CCCC DDDD&lt;/Certificate&gt;&lt;UseSSO vt=&quot;11&quot;&gt;0&lt;/UseSSO&gt;&lt;AffiliateApplicationName vt=&quot;8&quot;&gt;Name&lt;/AffiliateApplicationName&gt;&lt;/CustomProps&gt;"
    ///             PrimaryTransportSendHandler="BizTalkServerApplication"
    ///             SecondaryTransportAddress="http://localhost/senddata.asmx"
    ///             SecondaryTransportDeliveryNotification="None"
    ///             SecondaryTransportName="Test Transport 2"
    ///             SecondaryTransportOrderedDelivery="false"
    ///             SecondaryTransportProtocolName="SOAP"
    ///             SecondaryTransportRetryCount="5"
    ///             SecondaryTransportRetryInterval="2"
    ///             SecondaryTransportServiceWindowEnabled="true"
    ///             SecondaryTransportServiceWindowStartTime="07:00:00"
    ///             SecondaryTransportServiceWindowEndTime="19:00:00"    
    ///             SecondaryTransportTransportData="&lt;CustomProps&gt;&lt;URI vt=&quot;8&quot;&gt;http://localhost/senddata.asmx&lt;/URI&gt;&lt;ClientCertificate vt=&quot;8&quot;&gt;AAAA BBBB CCCC DDDD&lt;/ClientCertificate&gt;&lt;Password vt=&quot;8&quot;&gt;somepassword&lt;/Password&gt;&lt;ProxyAddress vt=&quot;8&quot;&gt;http://someproxy&lt;/ProxyAddress&gt;&lt;ProxyPassword vt=&quot;8&quot;&gt;somepassword&lt;/ProxyPassword&gt;&lt;ProxyPort vt=&quot;3&quot;&gt;8080&lt;/ProxyPort&gt;&lt;ProxyUsername vt=&quot;8&quot;&gt;someuser&lt;/ProxyUsername&gt;&lt;UseProxy vt=&quot;11&quot;&gt;-1&lt;/UseProxy&gt;&lt;Username vt=&quot;8&quot;&gt;someuser&lt;/Username&gt;&lt;AffiliateApplicationName vt=&quot;8&quot;&gt;Name&lt;/AffiliateApplicationName&gt;&lt;/CustomProps&gt;" 
    ///             SecondaryTransportSendHandler="BizTalkServerApplication"
    ///             Server="." 
    ///             Database="BizTalkMgmtDb" 
    ///              
    ///              />
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class Create : Microsoft.Sdc.Tasks.BizTalk2004.SendPort.Create
    {
        private string application;
        private string trackingTypes;
        private string sendPipelineData;
        private string receivePipelineData;
        private bool routeFailedMessages;
        private bool stopSendingOnFailure;
        private bool orderedDelivery;
        private string primaryTransportSendPortHandler;
        private string secondaryTransportSendPortHandler;

        /// <summary>
        /// The handler to use for the Send Port for the Secondary Transport
        /// </summary>
        public string SecondaryTransportSendPortHandler
        {
            get { return this.secondaryTransportSendPortHandler; }
            set { this.secondaryTransportSendPortHandler = value; }
        }

        /// <summary>
        /// The handler to use for the Send Port for the Primary Transport
        /// </summary>
        public string PrimaryTransportSendPortHandler
        {
            get { return this.primaryTransportSendPortHandler; }
            set { this.primaryTransportSendPortHandler = value; }
        }

        /// <summary>
        /// The custom receive pipeline data required to configure the pipeline. Takes an xml string.
        /// </summary>
        public string ReceivePipelineData
        {
            get { return this.receivePipelineData; }
            set { this.receivePipelineData = value; }
        }

        /// <summary>
        /// The custom send pipeline data required to configure the pipeline. Takes an xml string.
        /// </summary>
        public string SendPipelineData
        {
            get { return this.sendPipelineData;  }
            set { this.sendPipelineData = value; }
        }

        /// <summary>
        /// The application that this send port belongs to. If this is not specified, the BizTalk 2004 code 
        /// is executed.
        /// </summary>
        public string Application
        {
            get { return this.application; }
            set { this.application = value; }
        }

        /// <summary>
        /// Boolean indicating whether or not the send port stops sending messages on a failure
        /// </summary>
        public bool StopSendingOnFailure
        {
            get { return this.stopSendingOnFailure; }
            set { this.stopSendingOnFailure = value; }
        }

        /// <summary>
        /// Specifies whether or not the send port orders the delivery of messages.
        /// </summary>
        public bool OrderedDelivery
        {
            get { return this.orderedDelivery; }
            set { this.orderedDelivery = value; }
        }

        /// <summary>
        /// Specifies the desired level of document tracking for the send port. This is a ; delimited list
        /// of TrackingTypes. For example TrackPropertiesAfterReceivePipeline;TrackPropertiesAfterSendPipeline;TrackPropertiesBeforeReceivePipelineTrackPropertiesBeforeSendPipeline
        /// </summary>
        public new string TrackingTypes
        {
            get { return this.trackingTypes; }
            set { this.trackingTypes = value; }
        }

        /// <summary>
        /// Indicates whether or not failed messages are routed to failed message subscribers.
        /// </summary>
        public bool RouteFailedMessages
        {
            get { return this.routeFailedMessages; }
            set { this.routeFailedMessages = value; }
        }

        /// <summary>
        /// Execute
        /// </summary>
        protected override void InternalExecute()
        {
            if (string.IsNullOrEmpty(this.Application))
            {
                base.InternalExecute();
            }
            else
            {
                BtsCatalogExplorer explorer = this.GetBtsCatalogExplorer(this.Server, this.Database);

                Application app = explorer.Applications[this.Application];
                if (app != null)
                {
                    SendPort port = app.SendPorts[this.Name];
                    if (port == null)
                    {
                        port = app.AddNewSendPort(this.IsDynamic, this.IsTwoWay);
                        port.Name = this.Name;
                    }

                    port.Priority = this.Priority;
                    if (!string.IsNullOrEmpty(this.TrackingTypes))
                    {
                        Microsoft.BizTalk.ExplorerOM.TrackingTypes resultingTypes = 0;
                        string[] trackTypes = this.TrackingTypes.Split(';');
                        foreach (string type in trackTypes)
                        {
                            resultingTypes = resultingTypes | (Microsoft.BizTalk.ExplorerOM.TrackingTypes)Enum.Parse(typeof(Microsoft.BizTalk.ExplorerOM.TrackingTypes), type);
                        }

                        port.Tracking = resultingTypes;
                    }

                    // add the pipelines
                    string pipelineAssemblyName;
                    string pipelineTypeName;
                    SplitQualifiedTypeName(this.SendPipeline, out pipelineTypeName, out pipelineAssemblyName);
                    Pipeline p = explorer.Pipelines[pipelineTypeName, pipelineAssemblyName];
                    if (p != null)
                    {
                        port.SendPipeline = p;
                    }

                    port.SendPipelineData = (!string.IsNullOrEmpty(this.SendPipelineData)) ? this.SendPipelineData : port.SendPipelineData;
                    
                    if (this.IsTwoWay)
                    {
                        string recPipelineName;
                        string recPipelineAssemblyName;
                        SplitQualifiedTypeName(this.ReceivePipeline, out recPipelineName, out recPipelineAssemblyName);
                        Pipeline recPipeline = explorer.Pipelines[recPipelineName, recPipelineAssemblyName];
                        if (recPipeline != null)
                        {
                            port.ReceivePipeline = recPipeline;
                        }

                        port.ReceivePipelineData = (!string.IsNullOrEmpty(this.ReceivePipelineData)) ? this.ReceivePipelineData : port.ReceivePipelineData;    
                    }

                    // create the filter
                    port.Filter = (!string.IsNullOrEmpty(this.Filter)) ? this.Filter : port.Filter;

                    port.OrderedDelivery = this.OrderedDelivery;
                    port.StopSendingOnFailure = this.StopSendingOnFailure;

                    // Set the failed message routing
                    port.RouteFailedMessage = this.RouteFailedMessages;

                    // configure the primary transport
                    if (!string.IsNullOrEmpty(this.PrimaryTransportProtocolName))
                    {
                        port.PrimaryTransport.Address = this.PrimaryTransportAddress;
                        port.PrimaryTransport.OrderedDelivery = this.PrimaryTransportOrderedDelivery;
                        if (!string.IsNullOrEmpty(this.PrimaryTransportProtocolName))
                        {
                            port.PrimaryTransport.TransportType = explorer.ProtocolTypes[this.PrimaryTransportProtocolName];
                        }

                        port.PrimaryTransport.RetryCount = this.PrimaryTransportRetryCount;
                        port.PrimaryTransport.RetryInterval = this.PrimaryTransportRetryInterval;
                        port.PrimaryTransport.ServiceWindowEnabled = this.PrimaryTransportServiceWindowEnabled;
                        port.PrimaryTransport.TransportTypeData = (!string.IsNullOrEmpty(this.PrimaryTransportTransportData)) ? this.PrimaryTransportTransportData : port.PrimaryTransport.TransportTypeData;
                        if (!string.IsNullOrEmpty(this.PrimaryTransportSendPortHandler))
                        {
                            foreach (SendHandler sh in explorer.SendHandlers)
                            {
                                if (sh.Name == this.PrimaryTransportSendPortHandler && sh.TransportType.Name == this.PrimaryTransportProtocolName)
                                {
                                    port.PrimaryTransport.SendHandler = sh;
                                    break;
                                }
                            }
                        }
                    }

                    if (!string.IsNullOrEmpty(this.SecondaryTransportProtocolName))
                    {
                        // configure the secondary transport
                        port.SecondaryTransport.Address = this.SecondaryTransportAddress;
                        port.SecondaryTransport.OrderedDelivery = this.SecondaryTransportOrderedDelivery;
                        if (!string.IsNullOrEmpty(this.SecondaryTransportProtocolName))
                        {
                            port.SecondaryTransport.TransportType = explorer.ProtocolTypes[this.SecondaryTransportProtocolName];
                        }

                        port.SecondaryTransport.RetryCount = this.SecondaryTransportRetryCount;
                        port.SecondaryTransport.RetryInterval = this.SecondaryTransportRetryInterval;
                        port.SecondaryTransport.ServiceWindowEnabled = this.SecondaryTransportServiceWindowEnabled;
                        port.SecondaryTransport.TransportTypeData = (!string.IsNullOrEmpty(this.SecondaryTransportTransportData)) ? this.SecondaryTransportTransportData : port.SecondaryTransport.TransportTypeData;
                        if (!string.IsNullOrEmpty(this.SecondaryTransportSendPortHandler))
                        {
                            foreach (SendHandler sh in explorer.SendHandlers)
                            {
                                if (sh.Name == this.SecondaryTransportSendPortHandler && sh.TransportType.Name == this.SecondaryTransportProtocolName)
                                {
                                    port.PrimaryTransport.SendHandler = sh;
                                    break;
                                }
                            }
                        }
                    }

                    // add the maps
                    if (this.InboundMaps != null)
                    {
                        foreach (string qualifiedMapName in this.InboundMaps)
                        {
                            string mapName;
                            string assemblyName;
                            SplitQualifiedTypeName(qualifiedMapName, out mapName, out assemblyName);
                            port.InboundTransforms.Add(explorer.Transforms[mapName, assemblyName]);
                        }
                    }

                    if (this.OutboundMaps != null)
                    {
                        foreach (string qualifiedMapName in this.OutboundMaps)
                        {
                            string mapName;
                            string assemblyName;
                            SplitQualifiedTypeName(qualifiedMapName, out mapName, out assemblyName);
                            port.OutboundTransforms.Add(explorer.Transforms[mapName, assemblyName]);
                        }
                    }
                    
                    explorer.SaveChanges();
                }
                else
                {
                    Log.LogError(string.Format(CultureInfo.InvariantCulture, "Application not found: {0}", this.Application));
                    return;
                }
            }
        }
    }
}
